"""
仓库管理模块
提供仓库的克隆、更新、状态检查等功能
"""
import os
import subprocess
from pathlib import Path
from typing import List, Dict
from config import Config
from i18n import t


class RepoManager:
    """仓库管理器"""
    
    def __init__(self, config: Config = None):
        """
        初始化仓库管理器
        :param config: 配置对象
        """
        self.config = config or Config()
        self.workspace = Path(self.config.get_workspace())
        self.workspace.mkdir(parents=True, exist_ok=True)
    
    def get_repo_path(self, repo: str) -> Path:
        """获取仓库本地路径"""
        return self.workspace / repo
    
    def clone(self, repo: str, branch: str, depth: int = 1, username: str = None) -> bool:
        """
        克隆仓库到指定分支（从用户的 fork 仓克隆）
        如果目标分支不存在，会先克隆 base 分支，然后创建并切换到目标分支
        :param repo: 仓库名
        :param branch: 分支名（必须指定）
        :param depth: 克隆深度，1 表示浅克隆
        :param username: 用户名（必须提供，从该用户的 fork 仓克隆）
        :return: 是否成功
        """
        if not username:
            print(t("repo_manager.error_username_is_required_to_clone"))
            return False
        
        repo_path = self.get_repo_path(repo)
        repo_url = self.config.get_repo_url(repo, username)
        
        # 如果已存在，先删除
        if repo_path.exists():
            print(t("repo_manager.repository_repo_already_exists_at_path", repo=repo, path=repo_path))
            return True
        
        try:
            # 先尝试克隆目标分支
            cmd = ["git", "clone", "--branch", branch, "--single-branch"]
            if depth:
                cmd.extend(["--depth", str(depth)])
            cmd.extend([repo_url, str(repo_path)])
            
            result = subprocess.run(cmd, cwd=self.workspace, capture_output=True, text=True)
            if result.returncode == 0:
                print(t("repo_manager.cloned_repo_branch_branch_from_user", repo=repo, branch=branch, user=username))
                return True
            else:
                print(t("repo_manager.failed_to_clone_repo_error", repo=repo, error=result.stderr))
                return False
        except Exception as e:
            print(t("repo_manager.error_cloning_repo_error", repo=repo, error=e))
            return False
    
    def _ensure_upstream_remote(self, repo_path: Path, repo: str) -> bool:
        """
        确保存在 upstream remote（指向 Cangjie 主仓）
        :param repo_path: 仓库路径
        :param repo: 仓库名
        :return: 是否成功
        """
        try:
            # 检查是否已有 upstream remote
            result = subprocess.run(
                ["git", "remote", "get-url", "upstream"],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            if result.returncode == 0:
                # upstream 已存在
                return True
            
            # 添加 upstream remote
            upstream_url = self.config.get_repo_url(repo, None)  # None 表示主仓
            result = subprocess.run(
                ["git", "remote", "add", "upstream", upstream_url],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            if result.returncode == 0:
                print(t("repo_manager.added_upstream_remote_for_repo", repo=repo))
                return True
            else:
                print(t("repo_manager.warning_failed_to_add_upstream_remote", repo=repo, error=result.stderr))
                return False
        except Exception as e:
            print(t("repo_manager.warning_error_ensuring_upstream_remote_for", repo=repo, error=e))
            return False
    
    def _parse_repo_path_from_url(self, url: str) -> str:
        """
        从 Git URL 中解析出仓库路径（组织名/仓库名）
        例如: https://gitcode.com/Cangjie/cangjie_compiler.git -> Cangjie/cangjie_compiler
              git@gitcode.com:Cangjie/cangjie_compiler.git -> Cangjie/cangjie_compiler
        :param url: Git URL
        :return: 仓库路径（组织名/仓库名），如果解析失败则返回 None
        """
        try:
            # 移除 .git 后缀
            url = url.replace('.git', '').rstrip('/')
            
            # 处理 HTTPS URL: https://gitcode.com/Cangjie/cangjie_compiler
            if 'gitcode.com/' in url:
                parts = url.split('gitcode.com/')
                if len(parts) > 1:
                    repo_path = parts[1]
                    return repo_path
            
            # 处理 SSH URL: git@gitcode.com:Cangjie/cangjie_compiler
            if 'gitcode.com:' in url:
                parts = url.split('gitcode.com:')
                if len(parts) > 1:
                    repo_path = parts[1]
                    return repo_path
            
            return None
        except Exception:
            return None
    
    def _fetch_remote_branches(self, repo_path: Path, remote: str, required: bool = True) -> bool:
        """
        拉取指定 remote 的所有分支信息
        :param repo_path: 仓库路径
        :param remote: remote 名称（如 origin/upstream）
        :param required: 是否必须成功，如果为 True 失败则返回 False
        :return: 拉取是否成功或跳过（对于非 required 的 remote）
        """
        try:
            # 确认 remote 是否存在
            remote_check = subprocess.run(
                ["git", "remote", "get-url", remote],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            if remote_check.returncode != 0:
                if required:
                    print(t("repo_manager.remote_remote_not_found_in_repo", remote=remote, repo=repo_path.name))
                    return False
                # 非必须 remote 缺失则静默跳过
                return True
            
            fetch_result = subprocess.run(
                ["git", "fetch", remote, "--prune"],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            if fetch_result.returncode != 0:
                if required:
                    print(t("repo_manager.failed_to_fetch_all_branches_from", remote=remote, error=fetch_result.stderr))
                    return False
                else:
                    print(t("repo_manager.warning_failed_to_fetch_remote_error", remote=remote, error=fetch_result.stderr))
            return True
        except Exception as e:
            if required:
                print(t("repo_manager.error_fetching_remote_remote_in_repo", remote=remote, repo=repo_path.name, error=e))
                return False
            print(t("repo_manager.warning_error_fetching_remote_remote_in", remote=remote, repo=repo_path.name, error=e))
            return True
    
    def sync(self, repo: str, force: bool = False) -> bool:
        """
        同步仓库（从上游仓 Cangjie 主仓同步）
        基于 base 分支（通常是 main）从 upstream 同步，然后合并到当前分支
        :param repo: 仓库名
        :param force: 是否强制同步（强制拉取，丢弃本地更改）
        :return: 是否成功
        """
        repo_path = self.get_repo_path(repo)
        
        if not repo_path.exists():
            print(t("repo_manager.repository_repo_does_not_exist_use", repo=repo))
            return False
        
        try:
            # 获取当前分支
            result = subprocess.run(
                ["git", "rev-parse", "--abbrev-ref", "HEAD"],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            if result.returncode != 0:
                print(t("repo_manager.failed_to_get_current_branch_for", repo=repo))
                return False
            
            current_branch = result.stdout.strip()
            
            # 获取 base 分支（PR 目标分支，通常是 main）
            base_branch = self.config.get_base_branch()
            
            # 确保存在 upstream remote
            self._ensure_upstream_remote(repo_path, repo)
            
            # 拉取 upstream 和 origin 的所有分支信息
            if not self._fetch_remote_branches(repo_path, "upstream", required=True):
                pass
            if not self._fetch_remote_branches(repo_path, "origin", required=False):
                # origin 缺失或失败时继续，但已发出提示
                pass
            
            if force:
                print(t("repo_manager.force_syncing_repo_from_upstream_base", repo=repo, branch=base_branch))
                subprocess.run(
                    ["git", "fetch", "upstream", base_branch],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                result = subprocess.run(
                    ["git", "reset", "--hard", f"upstream/{base_branch}"],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                if result.returncode == 0:
                    print(t("repo_manager.force_synced_repo_from_upstream_base", repo=repo, branch=base_branch))
                    return True
                else:
                    print(t("repo_manager.failed_to_force_sync_repo_error", repo=repo, error=result.stderr))
                    return False
            else:
                print(t("repo_manager.syncing_repo_from_upstream_base_branch", repo=repo, branch=base_branch))
                fetch_result = subprocess.run(
                    ["git", "fetch", "upstream", base_branch],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                
                if fetch_result.returncode != 0:
                    print(t("repo_manager.failed_to_fetch_upstream_for_repo", repo=repo, error=fetch_result.stderr))
                    return False
                
                # 检查是否有更新（比较当前分支和 upstream/base_branch）
                check_result = subprocess.run(
                    ["git", "rev-list", "--left-right", "--count", f"{current_branch}...upstream/{base_branch}"],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                
                if check_result.returncode == 0:
                    parts = check_result.stdout.strip().split('\t')
                    if len(parts) == 2:
                        behind_count = int(parts[1]) if parts[1].isdigit() else 0
                        if behind_count == 0:
                            print(t("repo_manager.repo_is_already_up_to_date", repo=repo, branch=base_branch))
                            return True
                
                # 合并 upstream/base_branch 的更改到当前分支
                result = subprocess.run(
                    ["git", "merge", f"upstream/{base_branch}", "--no-edit"],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                
                if result.returncode == 0:
                    print(t("repo_manager.synced_repo_from_upstream_base_branch", repo=repo, base=base_branch, current=current_branch))
                    return True
                else:
                    error_output = result.stderr or result.stdout or ""
                    # 检测 unrelated histories 错误
                    if "unrelated histories" in error_output.lower() or "refusing to merge unrelated histories" in error_output.lower():
                        print(t("repo_manager.unrelated_histories_error", repo=repo, base=base_branch))
                        print(t("repo_manager.unrelated_histories_suggestion", base=base_branch))
                        return False
                    # 如果有冲突，提示用户
                    elif "CONFLICT" in error_output or "conflict" in error_output:
                        print(t("repo_manager.merge_conflict_in_repo_please_resolve", repo=repo))
                    else:
                        print(t("repo_manager.failed_to_sync_repo_error", repo=repo, error=error_output.strip()))
                    return False
        except Exception as e:
            print(t("repo_manager.error_syncing_repo_error", repo=repo, error=e))
            return False
    
    def status(self, repo: str) -> Dict:
        """
        获取仓库状态
        :param repo: 仓库名
        :return: 状态信息字典
        """
        repo_path = self.get_repo_path(repo)
        
        if not repo_path.exists():
            return {
                "exists": False,
                "repo": repo,
                "path": str(repo_path)
            }
        
        try:
            # 获取当前分支
            branch_result = subprocess.run(
                ["git", "rev-parse", "--abbrev-ref", "HEAD"],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            branch = branch_result.stdout.strip() if branch_result.returncode == 0 else "unknown"
            
            # 获取提交信息
            commit_result = subprocess.run(
                ["git", "log", "-1", "--oneline"],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            last_commit = commit_result.stdout.strip() if commit_result.returncode == 0 else "unknown"
            
            # 检查是否有未提交的更改
            status_result = subprocess.run(
                ["git", "status", "--porcelain"],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            has_changes = bool(status_result.stdout.strip())
            
            # 获取 base 分支（PR 目标分支，用于显示和比较）
            base_branch = self.config.get_base_branch()
            
            # 检查相对于 upstream 的 base 分支的领先和落后情况
            ahead_count = 0
            behind_count = 0
            is_behind = False
            upstream_repo_path = None
            
            # 先尝试获取 upstream 的 URL 和路径（即使后续检查失败，也能显示）
            try:
                # 确保 upstream remote 存在
                self._ensure_upstream_remote(repo_path, repo)
                
                # 获取 upstream 的 URL 并解析出组织名/仓库路径
                upstream_url_result = subprocess.run(
                    ["git", "remote", "get-url", "upstream"],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                if upstream_url_result.returncode == 0:
                    upstream_url = upstream_url_result.stdout.strip()
                    # 解析 URL: https://gitcode.com/Cangjie/cangjie_compiler.git
                    # 或: git@gitcode.com:Cangjie/cangjie_compiler.git
                    upstream_repo_path = self._parse_repo_path_from_url(upstream_url)
            except Exception:
                # 如果获取 URL 失败，upstream_repo_path 保持为 None
                pass
            
            # 尝试计算领先和落后情况
            try:
                # Fetch upstream 的 base 分支（不修改工作区）
                subprocess.run(
                    ["git", "fetch", "upstream", base_branch],
                    cwd=repo_path,
                    capture_output=True,
                    text=True,
                    timeout=30
                )
                
                # 检查本地分支相对于 upstream/base_branch 的领先和落后情况
                # ahead: 在本地分支中但不在 upstream/base_branch 中的提交
                ahead_result = subprocess.run(
                    ["git", "rev-list", "--count", f"upstream/{base_branch}..{branch}"],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                
                if ahead_result.returncode == 0:
                    ahead_count = int(ahead_result.stdout.strip() or "0")
                
                # behind: 检查 upstream/base_branch 是否已经被合并到本地分支
                # 如果 upstream 的所有提交都已经被包含在本地分支中，则 behind_count = 0
                merge_base_check = subprocess.run(
                    ["git", "merge-base", "--is-ancestor", f"upstream/{base_branch}", branch],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                
                if merge_base_check.returncode == 0:
                    # upstream 的所有提交都已经被包含在本地分支中
                    behind_count = 0
                    is_behind = False
                else:
                    # upstream 有新的提交未被合并到本地分支
                    # 计算在 upstream 中但不在本地分支中的提交数
                    behind_result = subprocess.run(
                        ["git", "rev-list", "--count", f"{branch}..upstream/{base_branch}"],
                        cwd=repo_path,
                        capture_output=True,
                        text=True
                    )
                    if behind_result.returncode == 0:
                        behind_count = int(behind_result.stdout.strip() or "0")
                        is_behind = behind_count > 0
            except Exception:
                # 如果检查失败，保持 ahead_count 和 behind_count 为 0
                pass
            
            # 检查相对于 origin（fork 仓）的领先和落后情况
            origin_ahead_count = 0
            origin_behind_count = 0
            origin_repo_path = None
            try:
                # 检查 origin remote 是否存在
                origin_check = subprocess.run(
                    ["git", "remote", "get-url", "origin"],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                
                if origin_check.returncode == 0:
                    origin_url = origin_check.stdout.strip()
                    # 解析 URL 获取仓库路径
                    origin_repo_path = self._parse_repo_path_from_url(origin_url)
                    
                    # Fetch origin 的当前分支（不修改工作区）
                    subprocess.run(
                        ["git", "fetch", "origin", branch],
                        cwd=repo_path,
                        capture_output=True,
                        text=True,
                        timeout=30
                    )
                    
                    # 检查本地分支相对于 origin/{branch} 的领先和落后情况
                    # ahead: 在本地分支中但不在 origin/{branch} 中的提交
                    origin_ahead_result = subprocess.run(
                        ["git", "rev-list", "--count", f"origin/{branch}..{branch}"],
                        cwd=repo_path,
                        capture_output=True,
                        text=True
                    )
                    
                    if origin_ahead_result.returncode == 0:
                        origin_ahead_count = int(origin_ahead_result.stdout.strip() or "0")
                    
                    # behind: 检查 origin/{branch} 是否已经被合并到本地分支
                    # 如果 origin 的所有提交都已经被包含在本地分支中，则 behind_count = 0
                    origin_merge_base_check = subprocess.run(
                        ["git", "merge-base", "--is-ancestor", f"origin/{branch}", branch],
                        cwd=repo_path,
                        capture_output=True,
                        text=True
                    )
                    
                    if origin_merge_base_check.returncode == 0:
                        # origin 的所有提交都已经被包含在本地分支中
                        origin_behind_count = 0
                    else:
                        # origin 有新的提交未被合并到本地分支
                        # 计算在 origin 中但不在本地分支中的提交数
                        origin_behind_result = subprocess.run(
                            ["git", "rev-list", "--count", f"{branch}..origin/{branch}"],
                            cwd=repo_path,
                            capture_output=True,
                            text=True
                        )
                        if origin_behind_result.returncode == 0:
                            origin_behind_count = int(origin_behind_result.stdout.strip() or "0")
            except Exception:
                # 如果检查失败，不显示领先/落后状态
                pass
            
            return {
                "exists": True,
                "repo": repo,
                "path": str(repo_path),
                "branch": branch,
                "base_branch": base_branch,
                "last_commit": last_commit,
                "has_changes": has_changes,
                "is_behind": is_behind,
                "ahead_count": ahead_count,
                "behind_count": behind_count,
                "origin_ahead_count": origin_ahead_count,
                "origin_behind_count": origin_behind_count,
                "upstream_repo_path": upstream_repo_path,
                "origin_repo_path": origin_repo_path
            }
        except Exception as e:
            return {
                "exists": True,
                "repo": repo,
                "path": str(repo_path),
                "error": str(e)
            }
    
    def clone_all(self, branch: str, depth: int = 1, username: str = None, repo_list: list = None) -> Dict[str, bool]:
        """
        克隆所有仓库到指定分支（从用户的 fork 仓克隆）
        :param branch: 分支名（所有仓库使用同一分支）
        :param depth: 克隆深度
        :param username: 用户名（必须提供，从该用户的 fork 仓克隆）
        :param repo_list: 要克隆的仓库列表（如果为 None，则使用配置中的所有仓库）
        :return: 每个仓库的克隆结果
        """
        if not username:
            print(t("repo_manager.error_username_is_required_to_clone"))
            return {}
        
        results = {}
        repos = repo_list if repo_list is not None else self.config.get_repos()
        
        print(t("repo_manager.cloning_count_repositories_to_branch_branch", count=len(repos), branch=branch, user=username))
        
        for repo in repos:
            results[repo] = self.clone(repo, branch, depth, username)
        
        return results
    
    def is_repo_initialized(self, repo: str) -> bool:
        """
        检查仓库是否已初始化
        :param repo: 仓库名
        :return: 是否已初始化
        """
        repo_path = self.get_repo_path(repo)
        if not repo_path.exists():
            return False
        # 检查是否是 git 仓库
        git_dir = repo_path / ".git"
        return git_dir.exists() or git_dir.is_file()
    
    def get_initialized_repos(self) -> List[str]:
        """
        获取已初始化的仓库列表
        :return: 已初始化的仓库列表
        """
        all_repos = self.config.get_repos()
        return [repo for repo in all_repos if self.is_repo_initialized(repo)]
    
    def sync_all(self, force: bool = False, repo_list: list = None) -> Dict[str, bool]:
        """
        同步已初始化的仓库
        :param force: 是否强制同步（强制拉取，丢弃本地更改）
        :param repo_list: 要同步的仓库列表（如果为 None，则同步所有已初始化的仓库）
        :return: 每个仓库的同步结果
        """
        results = {}
        if repo_list is not None:
            # 只同步指定的已初始化仓库
            repos = [r for r in repo_list if self.is_repo_initialized(r)]
        else:
            # 同步所有已初始化的仓库
            repos = self.get_initialized_repos()
        
        if not repos:
            return results
        
        action = "Force syncing" if force else "Syncing"
        print(t("repo_manager.action_count_initialized_repository_ies", action=action, count=len(repos)))
        
        for repo in repos:
            results[repo] = self.sync(repo, force)
        
        return results
    
    def status_all(self) -> List[Dict]:
        """
        获取所有已初始化仓库的状态
        :return: 状态信息列表
        """
        repos = self.get_initialized_repos()
        statuses = []
        
        for repo in repos:
            statuses.append(self.status(repo))
        
        return statuses
    
    def checkout_branch(self, repo: str, branch: str, create: bool = False) -> bool:
        """
        切换到指定分支（或创建新分支）
        :param repo: 仓库名
        :param branch: 分支名
        :param create: 如果分支不存在是否创建
        :return: 是否成功
        """
        repo_path = self.get_repo_path(repo)
        
        if not repo_path.exists():
            print(t("repo_manager.repository_repo_does_not_exist_use", repo=repo))
            return False
        
        try:
            # 检查分支是否存在
            result = subprocess.run(
                ["git", "rev-parse", "--verify", branch],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            branch_exists = result.returncode == 0
            
            if not branch_exists and create:
                # 创建新分支
                result = subprocess.run(
                    ["git", "checkout", "-b", branch],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                if result.returncode == 0:
                    print(t("repo_manager.created_and_switched_to_branch_branch", branch=branch, repo=repo))
                    return True
                else:
                    print(t("repo_manager.failed_to_create_branch_branch_in", branch=branch, repo=repo, error=result.stderr))
                    return False
            elif branch_exists:
                # 切换到已存在的分支
                result = subprocess.run(
                    ["git", "checkout", branch],
                    cwd=repo_path,
                    capture_output=True,
                    text=True
                )
                if result.returncode == 0:
                    print(t("repo_manager.switched_to_branch_branch_in_repo", branch=branch, repo=repo))
                    return True
                else:
                    print(t("repo_manager.failed_to_switch_to_branch_branch", branch=branch, repo=repo, error=result.stderr))
                    return False
            else:
                print(t("repo_manager.branch_branch_does_not_exist_in", branch=branch, repo=repo))
                return False
        except Exception as e:
            print(t("repo_manager.error_checking_out_branch_in_repo", repo=repo, error=e))
            return False
    
    def branch_exists(self, repo: str, branch: str) -> bool:
        """
        检查指定仓库中分支是否存在
        :param repo: 仓库名
        :param branch: 分支名
        :return: 分支是否存在
        """
        repo_path = self.get_repo_path(repo)
        
        if not repo_path.exists():
            return False
        
        try:
            result = subprocess.run(
                ["git", "rev-parse", "--verify", branch],
                cwd=repo_path,
                capture_output=True,
                text=True
            )
            return result.returncode == 0
        except Exception:
            return False
    
    def branch_exists_in_any(self, branch: str) -> bool:
        """
        检查分支是否在任何已初始化的仓库中存在
        :param branch: 分支名
        :return: 是否在任何仓库中存在
        """
        repos = self.get_initialized_repos()
        for repo in repos:
            if self.branch_exists(repo, branch):
                return True
        return False
    
    def checkout_all(self, branch: str, create: bool = False, overwrite: bool = False) -> Dict[str, bool]:
        """
        在所有仓库中切换到指定分支（或创建新分支）
        :param branch: 分支名（所有仓库使用同一分支）
        :param create: 如果分支不存在是否创建
        :param overwrite: 如果分支存在是否覆盖创建新分支
        :return: 每个仓库的操作结果
        """
        results = {}
        repos = self.config.get_repos()
        
        action = "Creating" if create else "Switching to"
        print(t("repo_manager.action_branch_branch_in_count_repositories", action=action, branch=branch, count=len(repos)))
        
        for repo in repos:
            if overwrite and self.branch_exists(repo, branch):
                # 删除已存在的分支并创建新分支
                repo_path = self.get_repo_path(repo)
                if repo_path.exists():
                    try:
                        # 先切换到其他分支（如果当前在目标分支上）
                        current_branch_result = subprocess.run(
                            ["git", "rev-parse", "--abbrev-ref", "HEAD"],
                            cwd=repo_path,
                            capture_output=True,
                            text=True
                        )
                        current_branch = current_branch_result.stdout.strip() if current_branch_result.returncode == 0 else None
                        
                        if current_branch == branch:
                            # 切换到默认分支或 main
                            base_branch = self.config.get_base_branch()
                            subprocess.run(
                                ["git", "checkout", base_branch],
                                cwd=repo_path,
                                capture_output=True,
                                text=True
                            )
                        
                        # 删除已存在的分支
                        subprocess.run(
                            ["git", "branch", "-D", branch],
                            cwd=repo_path,
                            capture_output=True,
                            text=True
                        )
                    except Exception:
                        pass  # 忽略错误，继续尝试创建
                
                # 创建新分支
                results[repo] = self.checkout_branch(repo, branch, create=True)
            else:
                results[repo] = self.checkout_branch(repo, branch, create)
        
        return results

